const SUFFIX = 'Storage';
const DEFAULT = 'Default';

function _generateStorageName(_Name: string) {
  return `${_Name || DEFAULT}${SUFFIX}`
}

export function InitStorage(_Name?: string | string[]) {
  if (Array.isArray(_Name)) {
    const [initName, ...otherNames] = _Name
    for (const nameItem of otherNames) {
      this.create(_generateStorageName(nameItem))
    }
    this.use(initName);
    return;
  }
  this.use(_Name)
}

export class Basic {
  #core: Storage;
  // 当前使用库名
  #current: string;
  // 初始化

  constructor(_Core?: Storage) {
    this.#core = _Core || sessionStorage
  }

  get storage(): {
    [name: string]: {
      value: any;
      time: number;
      expire: number;
    };
  } {
    return JSON.parse(this.#core.getItem(this.#current) || '{}');
  }

  set storage(_Value) {
    this.create(this.#current, _Value)
  }

  set name(_Name: string) {
    this.#current = _generateStorageName(_Name);
    // 看看是否存在对应数据库，如果不存在则初始化
    // 避免第1次赋值出现问题
    if (this.#core.getItem(this.#current) === null) {
      // 初始化仓库
      this.create(this.#current);
    }
  }

  get name() {
    return this.#current
  }

  /**
   * @name 切换storage
   * @description 如果不传则切回默认storage
   * @param _Name 要切换的storage名字
   */
  use(_Name = DEFAULT) {
    this.name = _Name;
  }

  /**
   * @name 创建storage
   * @param _Name 要创建的storage名字
   * @param _InitData storage初始值，默认一个空storage
   */
  create(_Name, _Value = {}) {
    this.#core.setItem(_Name, JSON.stringify(_Value));
  }

  /**
   * @description 对于对象和数组是追加模式，如果要清空或者重新赋值对象和数组，请使用reset
   * @param _Key 存储键 
   * @param _Value 要设置的值
   * @param _Expire 过期时效，默认为0永不过期
   */
  set(_Key: string, _Value, _Expire = 0) {
    const currentStorage = this.storage;
    if (currentStorage[_Key]) {
      const old = currentStorage[_Key];
      if (Array.isArray(old.value)) {
        // 如果传入的也是数组，则融合两个数组
        if (Array.isArray(_Value)) {
          for (const item of _Value) {
            old.value.push(item);
          }
        } else {
          old.value.push(_Value);
        }
      }
      // fix20210223：之前对象遍历的是旧值，如果旧值不存在新增的键，则新增的值永远不会赋值qvq~~。
      else if (typeof old.value === 'object') {
        Object.keys(_Value).forEach(function (_key) {
          old.value[_key] = _Value[_key];
        });
      }
      else {
        old.value = _Value;
      }
      currentStorage[_Key] = old;
    } else {
      currentStorage[_Key] = {
        value: _Value,
        time: Number((new Date().getTime() / 1000).toFixed(0)),
        expire: _Expire
      };
    }
    // 更新储存库
    this.storage = currentStorage;
  }

  get(_Key: string) {
    if (!this.storage[_Key]) {
      return undefined;
    }
    const storageValue = this.storage[_Key]
    if (storageValue.expire > 0) {
      // 检查缓存是否失效
      if (Number((new Date().getTime() / 1000).toFixed(0)) - storageValue.time > storageValue.expire) {
        // 使当前storage失效
        return this.reset(_Key);
      }
    }
    try {
      return JSON.parse(storageValue.value);
    } catch {
      return storageValue.value;
    }
  }

  /**
   * @name 删除storage
   * @description 不传名字删除当前storage
   * @description 指定名字删除指定storage
   */
  drop(_Name?: string) {
    this.#core.removeItem(_Name ? `${_Name}${SUFFIX}` : this.#current);
  }

  /**
   * @description 重置storage，如果重置不传值则默认是删除这个值
   * @param _Key 
   * @param _Value 
   */
  reset(_Key: string, _Value?: (_existValue: any) => any | any) {
    const storage = this.storage;
    const value = Object.prototype.toString.call(_Value) === '[object Function]' ? _Value(this.get(_Key)) : _Value ? _Value : undefined;
    // 如果有值，则用值重置项
    if (value) {
      storage[_Key].value = value;
    }
    // 如果无值，则删除项
    else {
      Reflect.deleteProperty(storage, _Key);
    }
    // 更新库
    this.storage = storage;
  }
}

export class StoragePlus extends Basic {
  constructor(_Name?: string | string[]) {
    super(localStorage)
    InitStorage.call(this, _Name)
  }
}

export class CachePlus extends Basic {
  constructor(_Name?: string | string[]) {
    super()
    InitStorage.call(this, _Name)
  }
}
